"""
WebSocket 服务器
用于与 Web Live2D 渲染器通信
"""

import asyncio
import json
import websockets
from typing import Set, Optional
import threading
from ..utils.logger import get_logger


class WebSocketServer:
    """WebSocket 服务器，用于实时推送 Live2D 参数"""
    
    def __init__(self, host: str = 'localhost', port: int = 8765):
        """
        初始化 WebSocket 服务器
        
        Args:
            host: 监听地址
            port: 监听端口
        """
        self.host = host
        self.port = port
        self.clients: Set[websockets.WebSocketServerProtocol] = set()
        self.server = None
        self.loop = None
        self.thread = None
        self.is_running = False
        self.logger = get_logger()
    
    async def _handle_client(self, websocket):
        """处理客户端连接"""
        self.clients.add(websocket)
        client_addr = websocket.remote_address
        self.logger.info(f"WebSocket 客户端已连接: {client_addr}")
        
        try:
            async for message in websocket:
                # 接收客户端消息（如果需要）
                try:
                    data = json.loads(message)
                    self.logger.debug(f"收到客户端消息: {data}")
                except json.JSONDecodeError:
                    self.logger.warning(f"无效的 JSON 消息: {message}")
        except websockets.exceptions.ConnectionClosed:
            self.logger.info(f"WebSocket 客户端已断开: {client_addr}")
        finally:
            self.clients.discard(websocket)
    
    async def _start_server(self):
        """启动 WebSocket 服务器"""
        self.server = await websockets.serve(
            self._handle_client,
            self.host,
            self.port
        )
        self.logger.info(f"✓ WebSocket 服务器已启动: ws://{self.host}:{self.port}")
        self.is_running = True
        
        # 保持服务器运行
        await asyncio.Future()  # 永远运行
    
    def _run_event_loop(self):
        """在新线程中运行事件循环"""
        self.loop = asyncio.new_event_loop()
        asyncio.set_event_loop(self.loop)
        
        try:
            self.loop.run_until_complete(self._start_server())
        except Exception as e:
            self.logger.error(f"WebSocket 服务器错误: {e}")
        finally:
            self.loop.close()
    
    def start(self):
        """启动服务器（在后台线程中）"""
        if self.is_running:
            self.logger.warning("WebSocket 服务器已在运行")
            return
        
        self.thread = threading.Thread(target=self._run_event_loop, daemon=True)
        self.thread.start()
        self.logger.info("WebSocket 服务器线程已启动")
    
    def stop(self):
        """停止服务器"""
        if not self.is_running:
            return
        
        self.is_running = False
        
        if self.loop and self.server:
            # 关闭服务器
            asyncio.run_coroutine_threadsafe(self._close_server(), self.loop)
        
        self.logger.info("WebSocket 服务器已停止")
    
    async def _close_server(self):
        """关闭服务器"""
        if self.server:
            self.server.close()
            await self.server.wait_closed()
        
        # 关闭所有客户端连接
        if self.clients:
            await asyncio.gather(
                *[client.close() for client in self.clients],
                return_exceptions=True
            )
            self.clients.clear()
    
    def broadcast(self, message: dict):
        """
        向所有连接的客户端广播消息
        
        Args:
            message: 要发送的消息字典
        """
        if not self.clients:
            return
        
        message_json = json.dumps(message, ensure_ascii=False)
        
        # 在事件循环中发送消息
        if self.loop:
            asyncio.run_coroutine_threadsafe(
                self._broadcast_async(message_json),
                self.loop
            )
    
    async def _broadcast_async(self, message: str):
        """异步广播消息"""
        if self.clients:
            await asyncio.gather(
                *[client.send(message) for client in self.clients],
                return_exceptions=True
            )
    
    def update_params(self, params: dict):
        """
        更新 Live2D 参数
        
        Args:
            params: 参数字典，例如 {'mouthOpen': 0.8, 'angleX': 5}
        """
        self.broadcast({
            'type': 'update_params',
            'params': params
        })
    
    def play_motion(self, motion_name: str):
        """
        播放动作
        
        Args:
            motion_name: 动作名称，如 'Idle', 'Tap@Body'
        """
        self.broadcast({
            'type': 'play_motion',
            'motion': motion_name
        })
    
    def set_expression(self, expression_name: str):
        """
        设置表情
        
        Args:
            expression_name: 表情名称
        """
        self.broadcast({
            'type': 'set_expression',
            'expression': expression_name
        })
    
    def has_clients(self) -> bool:
        """
        检查是否有客户端连接
        
        Returns:
            是否有客户端连接
        """
        return len(self.clients) > 0
    
    @property
    def client_count(self) -> int:
        """获取当前连接的客户端数量"""
        return len(self.clients)
